﻿/*
 * @Autor: PK
 * @Date: 2021/12/25 15:31:SS
 */

using ShkSimulation.core.exceptions;
using ShkSimulation.core.optimization.algorithm;
using ShkSimulation.core.optimization.extractor;
using ShkSimulation.core.optimization.extractor.result;
using ShkSimulation.core.optimization.impl;
using ShkSimulation.core.optimization.interfaces;
using ShkSimulation.core.optimization.variable;
using ShkSimulation.core.template;

namespace ShkSimulation.core.optimization {

    public class OptimizationNetworkBuilder {

        public OptimizationNetworkBuilder() {
            optimizationNetwork = new OptimizationNetwork();
        }

        private OptimizationNetwork optimizationNetwork;

        public OptimizationNetwork Build() {
            if (optimizationNetwork.Algorithm == null) {
                throw new ErrorParamException($"缺乏参数{nameof(optimizationNetwork.Algorithm)}");
            }
            if (optimizationNetwork.Config == null) {
                throw new ErrorParamException($"缺乏参数{nameof(optimizationNetwork.Config)}");
            }
            if (optimizationNetwork.EvaluationStrategy == null) {
                throw new ErrorParamException($"缺乏参数{nameof(optimizationNetwork.EvaluationStrategy)}");
            }
            if (optimizationNetwork.DecisionVariableExtractor == null) {
                throw new ErrorParamException($"缺乏参数{nameof(optimizationNetwork.DecisionVariableExtractor)}");
            }
            if (optimizationNetwork.TargetVariableExtractor == null) {
                throw new ErrorParamException($"缺乏参数{nameof(optimizationNetwork.TargetVariableExtractor)}");
            }
            if (optimizationNetwork.DecisionVariableConverter == null) {
                throw new ErrorParamException($"缺乏参数{nameof(optimizationNetwork.DecisionVariableConverter)}");
            }
            if (optimizationNetwork.UniqueIdGenerator == null) {
                throw new ErrorParamException($"缺乏参数{nameof(optimizationNetwork.UniqueIdGenerator)}");
            }
            if (optimizationNetwork.RealNetworkTemplate == null) {
                throw new ErrorParamException($"缺乏参数{nameof(optimizationNetwork.RealNetworkTemplate)}");
            }
            SetVariableVectorTemplate();
            return optimizationNetwork;
        }

        public OptimizationNetworkBuilder SetRealNetworkTemplate(CloneableNetwork network) {
            optimizationNetwork.RealNetworkTemplate = network;
			return this;
        }
        
        private void SetVariableVectorTemplate() {
            var temp = optimizationNetwork.DecisionVariableExtractor
                .ExtractNamedDecisionVariables(optimizationNetwork.RealNetworkTemplate.NetworkInput);
            var decisionVariableVector = optimizationNetwork.DecisionVariableConverter.Convert(temp);
            optimizationNetwork.VariableVectorTemplate = decisionVariableVector;
        }
        
        public OptimizationNetworkBuilder SetDecistionVariableExtractor(NamedDecisionVariableExtractor extractor){
            optimizationNetwork.DecisionVariableExtractor = extractor;
	        return this;
        }
        
        public OptimizationNetworkBuilder SetTargetVariableExtractor(TargetVariableExtractor extractor){
            optimizationNetwork.TargetVariableExtractor = extractor;
            return this;
        }
        
        public OptimizationNetworkBuilder SetAlgorithm(OptimizationAlgorithm algorithm){
            optimizationNetwork.Algorithm = algorithm;
	        return this;
        }
        
        public OptimizationNetworkBuilder SetConfig(OptimizationConfig config){
            optimizationNetwork.Config = config;
            return this;
        }
        
        public OptimizationNetworkBuilder SetUniqueIdGenerator(ParallelUniqueIdGenerator generator){
            optimizationNetwork.UniqueIdGenerator = generator;
            return this;
        }
        
        public OptimizationNetworkBuilder SetDecisionVariableConverter(DecisionVariableConverter<double> converter) {
            optimizationNetwork.DecisionVariableConverter = converter;
            return this;
        }
        
        public OptimizationNetworkBuilder SetEvaluationStrategy(ResultEvaluationStrategy strategy) {
            optimizationNetwork.EvaluationStrategy = strategy;
            return this;
        }

    }

}